﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Library.Linq;
using INDEX = System.UInt64;

namespace Library.Collections.Generic
{
    public static class ReadOnly
    {
        public static IDictionary<TKey, TValue> AsReadOnly<TKey, TValue>(IDictionary<TKey, TValue> dictionary)
        {
            if (dictionary.IsReadOnly) return dictionary;

            IAsReadOnly<IDictionary<TKey, TValue>> aro = dictionary as IAsReadOnly<IDictionary<TKey, TValue>>;
            IDictionary<TKey, TValue> ro;
            if (aro != null && aro.AsReadOnly(out ro))
                return ro;

            return new DictionaryWrapper<TKey, TValue>(dictionary);
        }
        public static IList<T> AsReadOnly<T>(IList<T> list)
        {
            if (list.IsReadOnly) return list;

            IAsReadOnly<IList<T>> aro = list as IAsReadOnly<IList<T>>;
            IList<T> ro;
            if (aro != null && aro.AsReadOnly(out ro))
                return ro;

            return new ListWrapper<T>(list);
        }
        public static IQueue<T> AsReadOnly<T>(IQueue<T> queue)
        {
            if (queue.IsReadOnly) return queue;

            IAsReadOnly<IQueue<T>> aro = queue as IAsReadOnly<IQueue<T>>;
            IQueue<T> ro;
            if (aro != null && aro.AsReadOnly(out ro))
                return ro;

            return new QueueWrapper<T>(queue);
        }
        public static IStack<T> AsReadOnly<T>(IStack<T> stack)
        {
            if (stack.IsReadOnly) return stack;

            IAsReadOnly<IStack<T>> aro = stack as IAsReadOnly<IStack<T>>;
            IStack<T> ro;
            if (aro != null && aro.AsReadOnly(out ro))
                return ro;

            return new StackWrapper<T>(stack);
        }
        public static IStack<T> AsReadOnly<T>(IStack<T> stack, Direction direction)
        {
            throw new NotImplementedException();
        }
        public static IVector<T> AsReadOnly<T>(IVector<T> vector)
        {
            if (vector.IsReadOnly) return vector;

            IAsReadOnly<IVector<T>> aro = vector as IAsReadOnly<IVector<T>>;
            IVector<T> ro;
            if (aro != null && aro.AsReadOnly(out ro))
                return ro;

            return vector is IQueryable<T> ? (IVector<T>)new VectorWrapperQueryable<T>(vector) : (IVector<T>)new VectorWrapper<T>(vector);
        }
        public static IVector<T> AsReadOnly<T>(T[] array)
        {
            return new Array<T>(array);
        }
        public static IVector<T> AsReadOnly<T>(T[] array, INDEX offset, INDEX count)
        {
            return new ArraySegment<T>(array, offset, count);
        }
        public static IVector<T> AsReadOnly<T>(T[] array, INDEX offset, INDEX count, Direction direction)
        {
            return direction == Direction.Forward ? (IVector<T>)new ArraySegment<T>(array, offset, count) : (IVector<T>)new ArraySegmentReversed<T>(array, offset, count);
        }

        internal sealed class Array<T> : IList<T>, IFirst<T>, IElementAt<T>, ILast<T>, ISkip<T>, ITake<T>
        {
            public Array(T[] array)
            {
                this.array = array;
            }
            T[] array;

            public bool Contains(T item, out INDEX index)
            {
                int _index = Array.IndexOf(array, item);
                if (_index >= 0)
                {
                    index = (INDEX)_index;
                    return true;
                }
                else
                {
                    index = 0;
                    return false;
                }
            }

            public T this[INDEX key]
            {
                get
                {
                    return array[key];
                }
                set
                {
                    throw new IsReadOnlyException();
                }
            }

            public bool Contains(T item)
            {
                return Array.IndexOf(array, item) >= 0;
            }

            public INDEX Count
            {
                get
                {
                    return (INDEX)array.Length;
                }
            }

            public IEnumerator<T> GetEnumerator()
            {
                return ((IEnumerable<T>)array).GetEnumerator();
            }

            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
            {
                return array.GetEnumerator();
            }

            public IEnumerator<T> GetEnumerator(Direction direction)
            {
                if (direction == Direction.Forward)
                {
                    return ((IEnumerable<T>)array).GetEnumerator();
                }
                else
                {
                    return new Library.Collections.Specialized.ArrayEnumeratorReversed<T>(array, 0, (ulong)array.Length);
                }
            }

            System.Collections.IEnumerator Specialized.IEnumerableDirection.GetEnumerator(Direction direction)
            {
                if (direction == Direction.Forward)
                {
                    return ((IEnumerable<T>)array).GetEnumerator();
                }
                else
                {
                    return new Library.Collections.Specialized.ArrayEnumeratorReversed<T>(array, 0, (ulong)array.Length);
                }
            }

            public bool IsReadOnly
            {
                get { return true; }
            }

            public bool First(out T item)
            {
                if (array.Length == 0)
                {
                    item = default(T);
                    return false;
                }
                item = array[0];
                return true;
            }

            public bool ElementAt(INDEX index, out T item)
            {
                if(index < (INDEX)array.Length)
                {
                    item = array[index];
                    return true;
                }
                item = default(T);
                return false;
            }

            public bool Last(out T item)
            {
                INDEX n = (INDEX)array.Length;
                if (n == 0)
                {
                    item = default(T);
                    return false;
                }
                item = array[n - 1];
                return true;
            }

            public IEnumerable<T> Skip(INDEX count)
            {
                if (count == 0)
                {
                    return this;
                }
                if (count < (INDEX)array.Length)
                {
                    return new ArraySegment<T>(array, count, (INDEX)array.Length - count);
                }
                else
                {
                    return new T[0];
                }
            }

            public IEnumerable<T> Take(INDEX count)
            {
                if (count == 0)
                {
                    return new T[0];
                }
                if (count < (INDEX)array.Length)
                {
                    return new ArraySegment<T>(array, 0, count);
                }
                else
                {
                    return this;
                }
            }

            public object Clone(Direction direction, Access access)
            {
                if (access == Access.Read)
                {
                    if (direction == Direction.Forward)
                    {
                        T[] _data = new T[array.Length];
                        Array.Copy(array, _data, array.Length);
                        return new ReadOnly.Array<T>(_data);
                    }
                    else
                    {
                        T[] _data = new T[array.Length];
                        for (int i = 0, n = array.Length; i < n; ++i)
                            _data[i] = array[n - 1 - i];
                        return new ReadOnly.Array<T>(_data);
                    }
                }
                else if (access == Access.ReadWrite)
                {
                    if (direction == Direction.Forward)
                    {
                        T[] _data = new T[array.Length];
                        Array.Copy(array, _data, array.Length);
                        return new Array<T>(_data);
                    }
                    else
                    {
                        T[] _data = new T[array.Length];
                        for (int i = 0, n = array.Length; i < n; ++i)
                            _data[i] = array[n - 1 - i];
                        return new Array<T>(_data);
                    }
                }
                else throw new NotSupportedException();
            }

            public object Clone(Direction direction)
            {
                if (direction == Direction.Forward)
                {
                    T[] _data = new T[array.Length];
                    Array.Copy(array, _data, array.Length);
                    return new Array<T>(_data);
                }
                else
                {
                    T[] _data = new T[array.Length];
                    for (int i = 0, n = array.Length; i < n; ++i)
                        _data[i] = array[n - 1 - i];
                    return new Array<T>(_data);
                }
            }

            public object Clone()
            {
                T[] _data = new T[array.Length];
                Array.Copy(array, _data, array.Length);
                return new Array<T>(_data);
            }

            public object Clone(Access access)
            {
                if (access == Access.Read)
                {
                    T[] _data = new T[array.Length];
                    Array.Copy(array, _data, array.Length);
                    return new ReadOnly.Array<T>(_data);
                }
                else if (access == Access.ReadWrite)
                {
                    T[] _data = new T[array.Length];
                    Array.Copy(array, _data, array.Length);
                    return new Array<T>(_data);
                }
                else throw new NotSupportedException();
            }

            public bool Add(T item, out INDEX index)
            {
                index = 0;
                return false;
            }

            public bool Insert(INDEX index, T item)
            {
                return false;
            }

            public bool RemoveAt(INDEX index)
            {
                return false;
            }

            public bool Add(T item)
            {
                return false;
            }

            public bool Remove(T item)
            {
                return false;
            }

            public bool Clear()
            {
                return false;
            }

            public bool IsFixedSize
            {
                get { return true; }
            }
        }

        internal sealed class ArraySegment<T> : IList<T>, IFirst<T>, IElementAt<T>, ILast<T>, ISkip<T>, ITake<T>
        {
            public ArraySegment(T[] array, INDEX offset, INDEX count)
            {
                this.array = array;
                this.offset = offset;
                this.count = count;
            }
            T[] array;
            INDEX offset;
            INDEX count;

            public bool Contains(T item, out INDEX index)
            {
                int _index = Array.IndexOf(array, item);
                if (_index >= 0)
                {
                    index = (INDEX)_index;
                    return true;
                }
                else
                {
                    index = 0;
                    return false;
                }
            }

            public T this[INDEX key]
            {
                get
                {
                    if (key < count)
                    {
                        return array[offset + key];
                    }
                    else
                    {
                        throw new IndexOutOfRangeException();
                    }
                }
                set
                {
                    throw new IsReadOnlyException();
                }
            }

            public bool Contains(T item)
            {
                return Array.IndexOf(array, item, (int)offset, (int)count) >= 0;
            }

            public INDEX Count
            {
                get
                {
                    return count;
                }
            }

            public IEnumerator<T> GetEnumerator()
            {
                return new Library.Collections.Specialized.ArrayEnumerator<T>(array, offset, count);
            }

            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
            {
                return new Library.Collections.Specialized.ArrayEnumerator<T>(array, offset, count);
            }

            public IEnumerator<T> GetEnumerator(Direction direction)
            {
                if (direction == Direction.Forward)
                {
                    return new Library.Collections.Specialized.ArrayEnumerator<T>(array, offset, count);
                }
                else
                {
                    return new Library.Collections.Specialized.ArrayEnumeratorReversed<T>(array, offset, count);
                }
            }

            System.Collections.IEnumerator Specialized.IEnumerableDirection.GetEnumerator(Direction direction)
            {
                if (direction == Direction.Forward)
                {
                    return new Library.Collections.Specialized.ArrayEnumerator<T>(array, offset, count);
                }
                else
                {
                    return new Library.Collections.Specialized.ArrayEnumeratorReversed<T>(array, offset, count);
                }
            }

            public bool IsReadOnly
            {
                get
                {
                    return true;
                }
            }

            public bool First(out T item)
            {
                if (count == 0)
                {
                    item = default(T);
                    return false;
                }
                item = array[offset];
                return true;
            }

            public bool ElementAt(INDEX index, out T item)
            {
                if (index < count)
                {
                    item = array[offset + index];
                    return true;
                }
                item = default(T);
                return false;
            }

            public bool Last(out T item)
            {
                if (count == 0)
                {
                    item = default(T);
                    return false;
                }
                item = array[offset + count - 1];
                return true;
            }

            public IEnumerable<T> Skip(INDEX count)
            {
                if (count == 0)
                {
                    return this;
                }
                if (count < this.count)
                {
                    return new ArraySegment<T>(array, offset + count, this.count - count);
                }
                else
                {
                    return new T[0];
                }
            }

            public IEnumerable<T> Take(INDEX count)
            {
                if (count == 0)
                {
                    return new T[0];
                }
                if (count < this.count)
                {
                    return new ArraySegment<T>(array, offset, count);
                }
                else
                {
                    return this;
                }                
            }

            public object Clone(Direction direction, Access access)
            {
                throw new NotImplementedException();
            }

            public object Clone(Direction direction)
            {
                throw new NotImplementedException();
            }

            public object Clone()
            {
                throw new NotImplementedException();
            }

            public object Clone(Access access)
            {
                throw new NotImplementedException();
            }

            public bool Add(T item, out INDEX index)
            {
                index = 0;
                return false;
            }

            public bool Insert(INDEX index, T item)
            {
                return false;
            }

            public bool RemoveAt(INDEX index)
            {
                return false;
            }

            public bool Add(T item)
            {
                return false;
            }

            public bool Remove(T item)
            {
                return false;
            }

            public bool Clear()
            {
                return false;
            }

            public bool IsFixedSize
            {
                get { return true; }
            }
        }

        internal sealed class ArraySegmentReversed<T> : IList<T>, IFirst<T>, IElementAt<T>, ILast<T>, ISkip<T>, ITake<T>
        {
            public ArraySegmentReversed(T[] array, INDEX offset, INDEX count)
            {
                this.array = array;
                this.offset = offset;
                this.count = count;
            }
            T[] array;
            INDEX offset;
            INDEX count;

            public T this[INDEX key]
            {
                get
                {
                    if (key < count)
                    {
                        return array[offset + count - 1 - key];
                    }
                    else
                    {
                        throw new IndexOutOfRangeException();
                    }
                }
                set
                {
                    throw new IsReadOnlyException();
                }
            }

            public bool Contains(T item, out INDEX index)
            {
                int n = Array.IndexOf(array, item, (int)offset, (int)count);
                if (n < 0)
                {
                    index = 0;
                    return false;
                }
                else
                {
                    index = offset + count - 1 - (INDEX)n;
                    return true;
                }
            }

            public bool Contains(T item)
            {
                return Array.IndexOf(array, item, (int)offset, (int)count) >= 0;
            }

            public INDEX Count
            {
                get { return count; }
            }

            public IEnumerator<T> GetEnumerator()
            {
                return new Library.Collections.Specialized.ArrayEnumeratorReversed<T>(array, offset, count);
            }

            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
            {
                return new Library.Collections.Specialized.ArrayEnumeratorReversed<T>(array, offset, count);
            }

            public IEnumerator<T> GetEnumerator(Direction direction)
            {
                if (direction == Direction.Forward)
                {
                    return new Library.Collections.Specialized.ArrayEnumeratorReversed<T>(array, offset, count);
                }
                else
                {
                    return new Library.Collections.Specialized.ArrayEnumerator<T>(array, offset, count);
                }
            }

            System.Collections.IEnumerator Specialized.IEnumerableDirection.GetEnumerator(Direction direction)
            {
                if (direction == Direction.Forward)
                {
                    return new Library.Collections.Specialized.ArrayEnumeratorReversed<T>(array, offset, count);
                }
                else
                {
                    return new Library.Collections.Specialized.ArrayEnumerator<T>(array, offset, count);
                }
            }

            public bool IsReadOnly
            {
                get { return true; }
            }

            public bool First(out T item)
            {
                if (count == 0)
                {
                    item = default(T);
                    return false;
                }
                item = array[offset + count - 1];
                return true;
            }

            public bool ElementAt(INDEX index, out T item)
            {
                if (index < count)
                {
                    item = array[offset + count - 1 - index];
                    return true;
                }
                item = default(T);
                return false;
            }

            public bool Last(out T item)
            {
                if (count == 0)
                {
                    item = default(T);
                    return false;
                }
                item = array[offset];
                return true;
            }

            public IEnumerable<T> Skip(INDEX count)
            {
                if (count == 0)
                {
                    return this;
                }
                if (count < this.count)
                {
                    return new ArraySegmentReversed<T>(array, offset, this.count - count);
                }
                else
                {
                    return new T[0];
                }
            }

            public IEnumerable<T> Take(INDEX count)
            {
                if (count == 0)
                {
                    return new T[0];
                }
                if (count < this.count)
                {
                    return new ArraySegmentReversed<T>(array, offset + this.count - count, count);
                }
                else
                {
                    return this;
                }
            }

            public object Clone(Direction direction, Access access)
            {
                throw new NotImplementedException();
            }

            public object Clone(Direction direction)
            {
                throw new NotImplementedException();
            }

            public object Clone()
            {
                throw new NotImplementedException();
            }

            public object Clone(Access access)
            {
                throw new NotImplementedException();
            }

            public bool Add(T item, out INDEX index)
            {
                index = 0;
                return false;
            }

            public bool Insert(INDEX index, T item)
            {
                return false;
            }

            public bool RemoveAt(INDEX index)
            {
                return false;
            }

            public bool Add(T item)
            {
                return false;
            }

            public bool Remove(T item)
            {
                return false;
            }

            public bool Clear()
            {
                return false;
            }

            public bool IsFixedSize
            {
                get { return true; }
            }
        }

        sealed class DictionaryWrapper<TKey, TValue> : IDictionary<TKey, TValue>
        {
            public DictionaryWrapper(IDictionary<TKey, TValue> dictionary)
            {
                this.dictionary = dictionary;
            }
            IDictionary<TKey, TValue> dictionary;

            public IEnumerable<TKey> Keys
            {
                get
                {
                    return dictionary.Keys;
                }
            }

            public IEnumerable<TValue> Values
            {
                get
                {
                    return dictionary.Values;
                }
            }

            public TValue this[TKey key]
            {
                get
                {
                    return dictionary[key];
                }
                set
                {
                    throw new IsReadOnlyException();
                }
            }

            public bool TryGetValue(TKey key, out TValue value)
            {
                return dictionary.TryGetValue(key, out value);
            }

            public bool TrySetValue(TKey key, TValue value)
            {
                return dictionary.TrySetValue(key, value);
            }

            public bool Contains(TKey key, TValue value)
            {
                return dictionary.Contains(key, value);
            }

            public bool ContainsKey(TKey key)
            {
                return dictionary.ContainsKey(key);
            }

            public IEnumerator<Tuple<TKey, TValue>> GetEnumerator()
            {
                return dictionary.GetEnumerator();
            }

            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
            {
                return dictionary.GetEnumerator();
            }

            public INDEX Count
            {
                get
                {
                    return dictionary.Count;
                }
            }

            public bool Add(TKey key, TValue value)
            {
                return false;
            }

            public bool Remove(TKey key, TValue value)
            {
                return false;
            }

            public bool RemoveKey(TKey key)
            {
                return false;
            }

            public bool IsReadOnly
            {
                get { return true; }
            }

            public bool Clear()
            {
                return false;
            }

            public bool IsFixedSize
            {
                get
                {
                    return true;
                }
            }
        }

        sealed class ListWrapper<T> : IList<T>
        {
            public ListWrapper(IList<T> list)
            {
                this.list = list;
            }
            IList<T> list;

            public bool Add(T item, out INDEX index)
            {
                index = 0;
                return false;
            }

            public bool Insert(INDEX index, T item)
            {
                return false;
            }

            public bool RemoveAt(INDEX index)
            {
                return false;
            }

            public T this[INDEX key]
            {
                get
                {
                    return list[key];
                }
                set
                {
                    throw new IsReadOnlyException();
                }
            }

            public bool Contains(T item, out INDEX index)
            {
                return list.Contains(item, out index);
            }

            public bool Contains(T item)
            {
                return list.Contains(item);
            }

            public INDEX Count
            {
                get { return list.Count; }
            }

            public IEnumerator<T> GetEnumerator()
            {
                return list.GetEnumerator();
            }

            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
            {
                return list.GetEnumerator();
            }

            public IEnumerator<T> GetEnumerator(Direction direction)
            {
                return list.GetEnumerator(direction);
            }

            System.Collections.IEnumerator Specialized.IEnumerableDirection.GetEnumerator(Direction direction)
            {
                return list.GetEnumerator(direction);
            }

            public bool IsReadOnly
            {
                get { return true; }
            }

            public bool Add(T item)
            {
                return false;
            }

            public bool Remove(T item)
            {
                return false;
            }

            public bool Clear()
            {
                return false;
            }

            public bool IsFixedSize
            {
                get { return true; }
            }
        }

        sealed class QueueWrapper<T> : IQueue<T>
        {
            public QueueWrapper(IQueue<T> queue)
            {
                this.queue = queue;
            }
            IQueue<T> queue;

            public bool Enqueue(T item)
            {
                return false;
            }

            public bool Dequeue(out T item)
            {
                item = default(T);
                return false;
            }

            public bool Peek(out T item)
            {
                return queue.Peek(out item);
            }

            public bool Contains(T item)
            {
                return queue.Contains(item);
            }

            public INDEX Count
            {
                get { return queue.Count; }
            }

            public IEnumerator<T> GetEnumerator()
            {
                return queue.GetEnumerator();
            }

            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
            {
                return queue.GetEnumerator();
            }

            public bool IsReadOnly
            {
                get { return true; }
            }
        }

        sealed class StackWrapper<T> : IStack<T>
        {
            public StackWrapper(IStack<T> stack)
            {
                this.stack = stack;
            }
            IStack<T> stack;

            public bool Peek(out T item)
            {
                return stack.Peek(out item);
            }

            public bool Contains(T item)
            {
                return stack.Contains(item);
            }

            public INDEX Count
            {
                get
                {
                    return stack.Count;
                }
            }

            public IEnumerator<T> GetEnumerator()
            {
                return stack.GetEnumerator();
            }

            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
            {
                return stack.GetEnumerator();
            }

            public IEnumerator<T> GetEnumerator(Direction direction)
            {
                return stack.GetEnumerator(direction);
            }

            System.Collections.IEnumerator Specialized.IEnumerableDirection.GetEnumerator(Direction direction)
            {
                return stack.GetEnumerator(direction);
            }

            public bool Pop()
            {
                return false;
            }

            public bool Pop(out T item)
            {
                item = default(T);
                return false;
            }

            public bool Push(T item)
            {
                return false;
            }

            public bool IsReadOnly
            {
                get { return true; }
            }
        }

        sealed class VectorWrapper<T> : IList<T>
        {
            public VectorWrapper(IVector<T> vector)
            {
                this.vector = vector;
            }
            IVector<T> vector;

            public bool Contains(T item, out INDEX index)
            {
                return vector.Contains(item, out index);
            }

            public T this[INDEX key]
            {
                get
                {
                    return vector[key];
                }
                set
                {
                    throw new IsReadOnlyException();
                }
            }

            public bool Contains(T item)
            {
                return vector.Contains(item);
            }

            public INDEX Count
            {
                get
                {
                    return vector.Count;
                }
            }

            public IEnumerator<T> GetEnumerator()
            {
                return vector.GetEnumerator();
            }

            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
            {
                return vector.GetEnumerator();
            }

            public IEnumerator<T> GetEnumerator(Direction direction)
            {
                return vector.GetEnumerator(direction);
            }

            System.Collections.IEnumerator Specialized.IEnumerableDirection.GetEnumerator(Direction direction)
            {
                return vector.GetEnumerator(direction);
            }

            public bool IsReadOnly
            {
                get { return true; }
            }

            public bool Add(T item, out INDEX index)
            {
                index = 0;
                return false;
            }

            public bool Insert(INDEX index, T item)
            {
                return false;
            }

            public bool RemoveAt(INDEX index)
            {
                return false;
            }

            public bool Add(T item)
            {
                return false;
            }

            public bool Remove(T item)
            {
                return false;
            }

            public bool Clear()
            {
                return false;
            }

            public bool IsFixedSize
            {
                get { return true; }
            }
        }

        sealed class VectorWrapperQueryable<T> : IList<T>, IQueryable<T>
        {
            public VectorWrapperQueryable(IVector<T> vector)
            {
                this.vector = vector;
            }
            IVector<T> vector;

            public bool Contains(T item, out INDEX index)
            {
                return vector.Contains(item, out index);
            }

            public T this[INDEX key]
            {
                get
                {
                    return vector[key];
                }
                set
                {
                    throw new IsReadOnlyException();
                }
            }

            public bool Contains(T item)
            {
                return vector.Contains(item);
            }

            public INDEX Count
            {
                get
                {
                    return vector.Count;
                }
            }

            public IEnumerator<T> GetEnumerator()
            {
                return vector.GetEnumerator();
            }

            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
            {
                return vector.GetEnumerator();
            }

            public IEnumerator<T> GetEnumerator(Direction direction)
            {
                return vector.GetEnumerator(direction);
            }

            System.Collections.IEnumerator Specialized.IEnumerableDirection.GetEnumerator(Direction direction)
            {
                return vector.GetEnumerator(direction);
            }

            public Type ElementType
            {
                get
                {
                    return ((IQueryable)vector).ElementType;
                }
            }

            public System.Linq.Expressions.Expression Expression
            {
                get
                {
                    return ((IQueryable)vector).Expression;
                }
            }

            public IQueryProvider Provider
            {
                get
                {
                    return ((IQueryable)vector).Provider;
                }
            }

            public bool IsReadOnly
            {
                get { return true; }
            }

            public bool Add(T item, out INDEX index)
            {
                index = 0;
                return false;
            }

            public bool Insert(INDEX index, T item)
            {
                return false;
            }

            public bool RemoveAt(INDEX index)
            {
                return false;
            }

            public bool Add(T item)
            {
                return false;
            }

            public bool Remove(T item)
            {
                return false;
            }

            public bool Clear()
            {
                return false;
            }

            public bool IsFixedSize
            {
                get { return true; }
            }
        }



        [DebuggerDisplay("Count={Count}")]
        internal sealed class Stack<T> : IStack<T>, IStack, IClearable, IFirst<T>, IElementAt<T>, ILast<T>, IReverse<T>
        {
            struct Enumerator : IEnumerator<T>, System.Collections.IEnumerator, IDisposable
            {
                internal Enumerator(Stack<T> stack)
                {
                    this.stack = stack;
                    index = -2;
                    version = stack.version;
                }

                Stack<T> stack;
                long index;
                INDEX version;

                public void Dispose()
                {
                    index = -1;
                }

                public bool MoveNext()
                {
                    if (version != stack.version)
                        throw new InvalidOperationException();

                    if (index == -2)
                        index = (long)stack.count;

                    return index != -1 && --index != -1;
                }

                public T Current
                {
                    get
                    {
                        if (index < 0)
                            throw new InvalidOperationException();

                        return stack.data[index];
                    }
                }

                public void Reset()
                {
                    if (version != stack.version)
                        throw new InvalidOperationException();

                    index = -2;
                }

                object System.Collections.IEnumerator.Current
                {
                    get
                    {
                        return Current;
                    }
                }
            }
            struct EnumeratorReversed : IEnumerator<T>, IDisposable
            {
                Stack<T> stack;
                long next;
                INDEX version;

                T current;

                public EnumeratorReversed(Stack<T> stack)
                    : this()
                {
                    this.stack = stack;
                    version = stack.version;
                }

                public void Dispose()
                {
                }

                public bool MoveNext()
                {
                    if (version != stack.version)
                        throw new InvalidOperationException();

                    if (next < 0)
                        return false;

                    if ((INDEX)next < stack.count)
                    {
                        current = stack.data[next++];
                        return true;
                    }

                    next = -1;
                    return false;
                }

                public T Current
                {
                    get { return current; }
                }

                public void Reset()
                {
                    if (version != stack.version)
                        throw new InvalidOperationException();

                    next = 0;
                }

                object System.Collections.IEnumerator.Current
                {
                    get
                    {
                        return current;
                    }
                }
            }
            struct ReversedStack : IStack<T>, IStack, IFirst<T>, IElementAt<T>, ILast<T>, IReverse<T>
            {
                public ReversedStack(Stack<T> stack)
                {
                    this.stack = stack;
                }
                internal Stack<T> stack;

                public bool Pop()
                {
                    return false;
                }

                public bool Pop(out T item)
                {
                    item = default(T);
                    return false;
                }

                public bool Push(T item)
                {
                    return false;
                }

                public bool Peek(out T item)
                {
                    if (stack.count == 0)
                    {
                        item = default(T);
                        return false;
                    }
                    item = stack.data[0];
                    return true;
                }

                public bool Contains(T item)
                {
                    return stack.Contains(item);
                }

                public INDEX Count
                {
                    get { return stack.count; }
                }

                public IEnumerator<T> GetEnumerator(Direction direction)
                {
                    if (direction == Direction.Forward)
                        return stack.GetEnumerator(Direction.Reverse);
                    else
                        return stack.GetEnumerator();
                }

                System.Collections.IEnumerator Specialized.IEnumerableDirection.GetEnumerator(Direction direction)
                {
                    if (direction == Direction.Forward)
                        return stack.GetEnumerator(Direction.Reverse);
                    else
                        return stack.GetEnumerator();
                }

                public IEnumerator<T> GetEnumerator()
                {
                    return stack.GetEnumerator(Direction.Reverse);
                }

                System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
                {
                    return stack.GetEnumerator(Direction.Reverse);
                }

                public bool IsReadOnly
                {
                    get { return true; }
                }

                public bool First(out T item)
                {
                    if (stack.count == 0)
                    {
                        item = default(T);
                        return false;
                    }
                    item = stack.data[0];
                    return true;
                }

                public bool ElementAt(INDEX index, out T item)
                {
                    if (index < stack.count)
                    {
                        item = stack.data[index];
                        return true;
                    }
                    item = default(T);
                    return false;
                }

                public bool Last(out T item)
                {
                    return stack.Peek(out item);
                }

                public IEnumerable<T> Reverse()
                {
                    return stack.IsReadOnly ? stack : ReadOnly.AsReadOnly(stack);
                }

                public bool Contains(T item, out INDEX index)
                {
                    int n = Array.IndexOf(stack.data, item, 0, (int)stack.count);
                    if (n < 0)
                    {
                        index = 0;
                        return false;
                    }
                    index = (INDEX)n;
                    return true;
                }

                public T this[INDEX index]
                {
                    get
                    {
                        if (index < stack.count)
                        {
                            return stack.data[index];
                        }
                        throw new IndexOutOfRangeException();
                    }
                }

                public bool Pop(out object item)
                {
                    item = null;
                    return false;
                }

                public bool Push(object item)
                {
                    return false;
                }

                public bool Peek(out object item)
                {
                    item = null;
                    return false;
                }

                public bool Contains(object item)
                {
                    if (item is T)
                    {
                        return stack.Contains((T)item);
                    }
                    else
                    {
                        return false;
                    }
                }
            }

            public Stack(IStackReadOnly<T> stack)
            {
                Stack<T> other_stack = stack as Stack<T>;
                if (other_stack != null)
                {
                    count = other_stack.count;
                    data = new T[count];
                    version = 0;
                    Array.Copy(other_stack.data, data, (int)count);
                }
                else if (stack is ReversedStack)
                {
                    ReversedStack reversed_stack = (ReversedStack)stack;
                    Stack<T> _stack = reversed_stack.stack;
                    count = _stack.count;
                    data = new T[count];
                    version = 0;
                    for (INDEX i = 0; i < count; ++i)
                        data[i] = _stack.data[count - i - 1];
                }
                else
                {
                    data = new T[0];
                    count = 0;
                    version = 0;
                    using (var enumerator = stack.GetEnumerator(Direction.Reverse))
                    {
                        while (enumerator.MoveNext())
                        {
                            Push(enumerator.Current);
                        }
                    }
                }
            }
            public Stack(T[] data, INDEX count)
            {
                this.data = data;
                this.count = count;
                this.version = 0;
            }

            T[] data;
            INDEX count;
            INDEX version;

            public bool Pop()
            {
                return false;
            }

            public bool Pop(out T item)
            {
                item = default(T);
                return false;
            }

            public bool Push(T item)
            {
                return false;
            }

            public bool Peek(out T item)
            {
                if (count == 0)
                {
                    item = default(T);
                    return false;
                }
                item = data[count - 1];
                return true;
            }

            public bool Contains(T item)
            {
                return Array.IndexOf(data, item, 0, (int)count) >= 0;
            }

            public INDEX Count
            {
                get
                {
                    return count;
                }
            }

            public bool Clear()
            {
                return false;
            }

            public IEnumerator<T> GetEnumerator()
            {
                return new Enumerator(this);
            }

            public IEnumerator<T> GetEnumerator(Direction direction)
            {
                return direction == Direction.Reverse ? (IEnumerator<T>)new EnumeratorReversed(this) : (IEnumerator<T>)new Enumerator(this);
            }

            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
            {
                return new Enumerator(this);
            }

            System.Collections.IEnumerator Library.Collections.Specialized.IEnumerableDirection.GetEnumerator(Direction direction)
            {
                return direction == Direction.Reverse ? (System.Collections.IEnumerator)new EnumeratorReversed(this) : (System.Collections.IEnumerator)new Enumerator(this);
            }

            public bool IsReadOnly
            {
                get
                {
                    return true;
                }
            }

            bool IStack.Pop(out object item)
            {
                item = default(T);
                return false;
            }

            bool IStack.Push(object item)
            {
                return false;
            }

            bool IStackReadOnly.Peek(out object item)
            {
                if (count == 0)
                {
                    item = default(T);
                    return false;
                }
                item = data[count - 1];
                return true;
            }

            bool IContainer.Contains(object item)
            {
                if (!(item is T)) return false;
                return Array.IndexOf(data, item, 0, (int)count) >= 0;
            }

            bool IFirst<T>.First(out T item)
            {
                return Peek(out item);
            }

            bool IElementAt<T>.ElementAt(INDEX index, out T item)
            {
                if (count == 0 || index >= count)
                {
                    item = default(T);
                    return false;
                }
                item = data[(count - 1) - index];
                return true;
            }

            bool ILast<T>.Last(out T item)
            {
                if (count == 0)
                {
                    item = default(T);
                    return false;
                }
                item = data[0];
                return true;
            }

            IEnumerable<T> IReverse<T>.Reverse()
            {
                return new ReversedStack(this);
            }

            public IStack<T> Clone()
            {
                T[] new_data = new T[count];
                Array.Copy(data, new_data, (int)count);
                return new ReadOnly.Stack<T>(new_data, count);
            }

            public IStack<T> Clone(Access access)
            {
                if (access == Access.Write) throw new NotSupportedException();

                T[] new_data = new T[count];
                Array.Copy(data, new_data, (int)count);

                if (access == Access.ReadWrite)
                {
                    return new Stack<T>(new_data, count);
                }
                else
                {
                    return new ReadOnly.Stack<T>(new_data, count);
                }
            }
        }
    }
}
